package com.lzw.mysqldemo.mypool;

import java.util.Iterator;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class LzwObjectPool<T> {


    public static void main(String[] args) throws Exception {
        LzwObjectPool<LzwObject> lzwObjectPool = new LzwObjectPool<>();

        //===============================================================
//        LzwObject lzwObject1 = lzwObjectPool.borrowObject();
//        System.out.println("干活........1");
//        lzwObjectPool.returnObject(lzwObject1);
//        LzwObject lzwObject2 = lzwObjectPool.borrowObject();
//        System.out.println("干活........2");
//        lzwObjectPool.returnObject(lzwObject2);

        //===============================================================
        ExecutorService es = Executors.newFixedThreadPool(10);
        final CountDownLatch countDownLatch1 = new CountDownLatch(1);
        final CountDownLatch countDownLatch2 = new CountDownLatch(10);
        for(int i =0;i<10;i++){
            final int index= i;
            es.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        countDownLatch1.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    LzwObject l = lzwObjectPool.borrowObject();
                    if(l == null){
                        System.out.println("index:"+index+",获得阻塞超时！！！");
                    } else {
                        System.out.println("index:"+index+",获得对象："+l);
                        try {
                            Thread.sleep(200);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        try {
                            lzwObjectPool.returnObject(l);
                            System.out.println("index:"+index+",返还对象："+l);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    countDownLatch2.countDown();
                }
            });
        }
        Thread.sleep(4000);
        countDownLatch1.countDown();
        countDownLatch2.await();
        System.out.println("创建对象数："+lzwObjectPool.allSize.get());


        //===============================================================
        //回收测试
        lzwObjectPool.minidle = 3;
        lzwObjectPool.evict();
    }





    //空闲对象表
    private BlockingQueue<LzwPoolObject<T>> idleObjects = new LinkedBlockingQueue<>();
    //所有的对象表
    private ConcurrentHashMap<T,LzwPoolObject<T>> allObjects = new ConcurrentHashMap();
    //全部对象数
    private AtomicInteger allSize = new AtomicInteger(0);

    private RealObjectFactory<T> factory = new RealObjectFactory<>();
    private EvictionPolicy<T> evictionPolicy = new EvictionPolicy<>();

    //请求限制
    private int maxSize = 100;
    private int exhaustHandle = 2;//借出对象时，空闲对象耗尽，怎么处理：1 异常；2阻塞超时
    private long timout = -1;//超时时间
    //健康检测
    private boolean testOnBorrow = false;
    private boolean testOnReturn = false;
    private boolean testOnWhile = false;
    //弹性回收
    private int minidle = 3;
    private int maxidle = 10;
    private long idletime;

    //借出对象
    public T borrowObject(){
        LzwPoolObject<T> lzwPoolObject = null;
        while (lzwPoolObject == null) {
            lzwPoolObject = idleObjects.poll();//不阻塞，没有就返回null
            boolean create = false;
            if (lzwPoolObject == null) {
                int lll = allSize.incrementAndGet();
                if (lll <= maxSize) {//没有到最大就去创建新的，增加allSize，已被使用不需要添加到idleObjects
                    //先比较后累加，复合操作 应解决并发安全问题
                    lzwPoolObject = factory.mackObject();
                    allObjects.put(lzwPoolObject.getObj(),lzwPoolObject);
                    create = true;
                    System.out.println("创建对象第" + lll + "," + lzwPoolObject);
                } else {
                    allSize.decrementAndGet();
                    switch (exhaustHandle) {
                        case 1://异常
                            throw new RuntimeException("池中资源已经耗尽！！！");
                        case 2:
                            if (timout <= 0) {//一直阻塞
                                try {
                                    lzwPoolObject = idleObjects.take();
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            } else {//阻塞到超时
                                try {
                                    lzwPoolObject = idleObjects.poll(timout, TimeUnit.MILLISECONDS);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                if(lzwPoolObject == null){
                                    throw new RuntimeException("Timeout waiting for idle object");
                                }
                            }
                            break;
                    }
                }
            }
            if (lzwPoolObject != null) {
                //健康检查
                if (testOnBorrow) {
                    if (!factory.validateObject(lzwPoolObject)) {
                        //检查未通过，销毁实例，从表中移除
                        allObjects.remove(lzwPoolObject.getObj());
                        allSize.decrementAndGet();
                        factory.destoryObject(lzwPoolObject);
                        if(create){
                            throw new RuntimeException("create error.....");
                        }
                    }
                }
            }
        }
        return lzwPoolObject.getObj();
    }

    //返还对象
    public void returnObject(T obj) throws Exception{
        LzwPoolObject<T> lzwPoolObject = allObjects.get(obj);
        if(lzwPoolObject != null){
            boolean destory = false;
            if(testOnReturn){
                if(!factory.validateObject(lzwPoolObject)){
                    //检查未通过，销毁实例，从表中移除
                    allSize.decrementAndGet();
                    allObjects.remove(lzwPoolObject.getObj());
                    factory.destoryObject(lzwPoolObject);
                    destory = true;
                }
            }
            if(!destory){//若验证通过未销毁，判断是否超出最大空闲数量
                if(maxidle < idleObjects.size()){
                    allSize.decrementAndGet();
                    allObjects.remove(lzwPoolObject.getObj());
                    factory.destoryObject(lzwPoolObject);
                    destory = true;
                }
            }
            if(!destory){
                idleObjects.put(lzwPoolObject);
            }
        }
    }

    //弹性回收，周期扫描
    public void evict(){
        if (idleObjects.size() > 0) {
            Iterator<LzwPoolObject<T>> iterator = idleObjects.iterator();
            while (iterator.hasNext()){
                LzwPoolObject<T> object = iterator.next();
                boolean evict = evictionPolicy.evict(object,minidle,idleObjects.size());
                if(!evict){
                    //健康检测
                    if(testOnWhile && !factory.validateObject(object)){
                        evict = true;
                    }
                }
                if(evict){//驱逐
                    allSize.decrementAndGet();
                    idleObjects.remove(object);
                    allObjects.remove(object.getObj());
                    factory.destoryObject(object);
                }
            }
        }
    }



}
